Jak napisać C++ DLL dla VB?
Wiemy, że wykonywanie
kodu VB jest wolniejsze (dużo) od wykonywania kodu samego C++. Choć VB korzysta
z kompilatora C++ to jednak zbyt dużo jest w kodzie (i najwięcej w runtime DLL)
pozostałości ze starego VB. Chociaż kompilujemy program do N-kodu to i tak
typy zmiennych nie są typami z C++ ale z VB...
Na szczęście możemy importować funkcje z zewnętrznych bibliotek, nie tylko
z VB (Active X DLL, OCX), ale także z C (Windows API) oraz C++. Różnica, którą
powinniśmy zauważyć, między aplikacjami C a C++ jest taka, że aplikacje języka
C nie wymagają żadnych runtime'ów w postaci DLL. Wystarczy im Windows API.
Znając (przynajmniej w stopniu początkującym) język C++ możemy stworzyć
bibliotekę DLL którą można by używać w kodzie VB. Zadanie to jednak jest
trudniejsze niż tworzenie ActiveX DLL'ów (m.in. dlatego, że mamy do czynienia
z C++).
Chociaż mam zainstalowane obydwa konkurencyjne edytory RAD języka C++, to
wybieram dla aplikacji narzędzie Borlanda, a Visual'a C++ używam do zastosowań
poważnych (właśnie takich jak DLL'e). Z tego powodu, że eksportowanie
funkcji w dwóch tych różnych środowiskach jest inne, to poświęcę ten
artykuł jedynie VC++. Mam nadzieję, że nikt nie będzie na mnie zły, ponieważ
piszę tutaj dużo o C++ a nie o VB. Myślę, że należy sobie poszerzać
horyzonty, a na początek używać C++ jedynie jako podpory.
Architektura biblioteki DLL
Biblioteka DLL na pozór nie różni się od zwykłego pliku wykonywalnego.
Posiada wszystkie jego części, takie jak:
data, idata, rdata, reloc, text.
Różnicą jest to, że taka biblioteka posiada punkt wejściowy, zwany
DLLEntryPoint. W punkcie wyjściowym znajdują się informacje dotyczące
funkcji eksportowanych.
Taka biblioteka może mieć swoje funkcje wewnętrzne i eksportowane. My możemy
korzystać tylko z funkcji eksportowanych.
Nie będę się zagłębiał w strukturę takiej biblioteki, ponieważ każdy może
sobie ją zobaczyć, korzystając z kreatora (takiego wizard'a).
Jedną z najważniejszych aspektów, które musimy przedyskutować to konwencja
wywoływania. Można ją ustawić w menu Porject\Settings w zakładce C\C++,
ustawiając ComboBox'a na Code Generation. W tedy pojawi się opcja (w postaci
listy combo) "Calling Convention".
Tutaj nie ma kompromisu. VB może korzystać tylko z bibliotek gdzie zastosowano
odpowiednie konwencje. Dla bibliotek 16-bitowych jest to konwencja Pascal'a, a
dla 32-bitowych konwencja Standard Call (__stdcall).
Po wybraniu konwencji dla napisanego DLL'a, w którym eksportowane są jakieś
funkcje należy go skompilować i na razie wrzucić do katalogu systemowego
(C:\Windows\System\). Znając parametry (lepiej je sobie gdzieś zapisać)
danych funkcji moglibyśmy już niby zacząć korzystać z biblioteki. Wpisując
deklarację:
Declare [nazwa
funkcji] Lib "[nazwa pliku biblioteki]"
([argumenty]) As [typ zmiennej zwrotu (return)]
Na pewno wyskoczy nam błąd:
"Can't find DllEntryPoint [tutaj nazwa funkcji] in [tutaj nazwa
biblioteki]." I możemy pomyśleć, że biblioteka jest niekompatybilna.
Problem tkwi w tym, że nazwa funkcji jest odmienna od użytej w kodzie
biblioteki. Dodawane są do niej jakieś dziwne znaczki. Skąd to wiem? Plik
dumpbin.exe potrafi wyświetlić funkcje eksportowane (jak i ich numery) każdej
biblioteki DLL. W tej chwili staje się oczywiste, że należy skorzystać z
Alias'a.
Program dumpbin znajduje się w katalogu BIN, tam gdzie zainstalowany jest VC++.
Do jego zastosowania użyjemy konsoli, czyli 'Tryb MS-DOS'.
Używamy go z parametrem /EXPORTS i dalej podając ścieżkę do pliku,
najlepiej wynik zapisać do pliku, czyli wpiszemy (dla biblioteki dll.dll):
dumpbin.exe /exports c:\windows\system\dll.dll
>wynik.txt
Teraz wszystko co "wydrukowałby"
program dumpbin zostanie w pliku wynik.txt który potem będziemy mogli obejrzeć,
a potem skopiować interesującą nas nazwę funkcji i zastosować ją jako
alias. Tak zadeklarowana funkcja na pewno powinna już działać bez problemu.
Musimy pamiętać także o zachowaniu kompatybilności z VB, bowiem niektóre
funkcje mogą nie dać się użyć.
Marcin Porębski ( Doogie )
marcin.porebski@interia.pl